package unify.fileio;

/**
 * Some code from http://www.javacoffeebreak.com/books/extracts/javanotesv3/c10/s4.html
 */

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.logging.Logger;

import unify.data.Feed;
import unify.data.Season;
import unify.data.Show;


public class RSSParser {
	private Feed myFeed;
	private ArrayList<Show> rssShows;
	private final static Logger LOGGER = Logger.getLogger(RSSParser.class.getName());

	public RSSParser(Feed myFeed) {
		this.myFeed = myFeed;
	}

	public ArrayList<Show> parseFeed() {
		this.rssShows = new ArrayList<Show>();
		try {
			Object content = myFeed.getLink().getContent();
			if (content instanceof InputStream) {
				LOGGER.fine("Checking feed " + myFeed.getLabel() + " @ " + myFeed.getLink());
				Scanner in = new Scanner(new InputStreamReader((InputStream) content ));
				boolean isTitle = false;
				String newTitle = "";
				String link = "";
				String nextString = "";
				while(in.hasNext()) {
					nextString = nextString + in.next() + " ";
					if(nextString.contains("<title>") && nextString.contains("</title>")) {
						isTitle = true;
						newTitle = nextString.split("<title>")[1].split("</title>")[0].trim().replaceAll("&amp;", "&");
						if(newTitle.split(".*(&#)(\\d+)(;)").length>1) {
							int num = Integer.parseInt(newTitle.replaceAll(".*(&#)(\\d+)", "$2").split(";")[0]);
							char c = (char) num;
							newTitle = newTitle.split("(&#)(\\d+)(;)")[0] + c + newTitle.split("(&#)(\\d+)(;)")[1];
						}
						System.out.println("New title: " + newTitle);
						nextString = "";
					}
					else if(nextString.contains("<link>") && nextString.contains("</link>")) {
						link = nextString.split("<link>")[1].split("</link>")[0].trim();
						if(isTitle) {
							parseEp(newTitle, link);
							isTitle = false;
						}
						nextString = "";
					}
				}
				in.close();
			}
			else {
				LOGGER.warning("Error: url.getContent() returning type other than InputStream.");
			}
		}
		catch (MalformedURLException e) {
			LOGGER.warning("Malformed URL.");
		}
		catch (SecurityException e) {
			LOGGER.warning("Security error" + e.toString());
		}
		catch (IOException e) {
			LOGGER.warning("IO error: " + e.toString());
		}
		return this.rssShows;
	}

	private void parseEp(String newTitle, String link) {
		if(newTitle.split("[sS]\\d\\d[eE]\\d\\d").length>1) {
			parseMethod1(newTitle, link);
		}
		else if(newTitle.split("-\\ss\\d+\\s|\\se\\d+").length>1) {
			parseMethod2(newTitle, link);
		}
		else if(newTitle.split("\\d+x\\d+").length>1) {
			parseMethod3(newTitle, link);
		}
		else if(newTitle.contains(" Part")) {
			parseMethod4(newTitle, link);
		}
	}

	//Parses shows with format s00e00, also handles multiple episode tags, like S01E01-E03
	public void parseMethod1(String newTitle, String link) {
		String myTitle = newTitle.split("[sS]\\d\\d[eE]\\d\\d")[0];
		String title = myTitle.trim();
		try {
			int seasonInt = Integer.parseInt(newTitle.substring(myTitle.length()+1, myTitle.length()+3));
			int episodeInt = Integer.parseInt(newTitle.substring(myTitle.length()+4, myTitle.length()+6));
			//doneParsing(title, seasonInt, episodeInt, link);
			int lastEpisodeInt = episodeInt;
			if(newTitle.split("[sS]\\d\\d[eE]\\d\\d-[eE]\\d\\d").length>1) {
				lastEpisodeInt = Integer.parseInt(newTitle.substring(myTitle.length()+8, myTitle.length()+10));
			}
			for(int i=episodeInt;i<=lastEpisodeInt;i++) {
				doneParsing(title, seasonInt, i, link);
			}
			
		} catch (NumberFormatException e) {
			LOGGER.info("Invalid number format for " + newTitle.substring(myTitle.length()+2, myTitle.length()+4) + " or " + newTitle.substring(myTitle.length()+5, myTitle.length()+7) + " in " + newTitle);
		}
	}

	//Parses shows with format s# | e# (Specifically seen on hulu)
	private void parseMethod2(String newTitle, String link) {
		String title = newTitle.split("-\\ss\\d+\\s|\\se\\d+")[0].trim();
		String matched = newTitle.substring(title.length()+4, newTitle.length()-newTitle.split("-\\ss\\d+\\s\\|\\se\\d+")[1].length());
		String season = matched.split("\\s\\|")[0];
		String episode = matched.split("\\s\\|\\se")[1];
		try {
			int seasonInt = Integer.parseInt(season);
			int episodeInt = Integer.parseInt(episode);
			doneParsing(title, seasonInt, episodeInt, link);
		} catch (NumberFormatException e) {
			LOGGER.info("Invalid number format for " + season + " or " + episode + " in " + newTitle);
		}
	}

	//Parses shows with format #x#, used by TVRage and most British shows
	//Has a bug with "Something something [1280x720 resolution]"
	private void parseMethod3(String newTitle, String link) {
		String title = newTitle.split("\\d+x\\d+")[0].trim();
		String season = newTitle.split("x\\d+")[0].split(" ")[newTitle.split(" ").length-1].replaceAll("\\(", "");
		String episode = newTitle.split("\\d+x")[1].split(" ")[0].replaceAll("\\)", "");
		try {
			int seasonInt = Integer.parseInt(season);
			int episodeInt = Integer.parseInt(episode);
			//Special formatting seen at tvrage.com
			if(title.startsWith("- ")) {
				title = title.substring(1, title.length()-1).trim();
			}
			doneParsing(title, seasonInt, episodeInt, link);
		} catch (NumberFormatException e) {
			LOGGER.info("Invalid number format for " + season + " or " + episode + " in " + newTitle);
		}
	}

	//Parses mini series using format "part one" or "part01"
	private void parseMethod4(String newTitle, String link) {
		int episodeInt;

		String title = newTitle.split(" Part")[0].trim();
		String episode = newTitle.split(" Part")[1].substring(0, 2);
		try {
			episodeInt = Integer.parseInt(episode);
		} catch (NumberFormatException e) {
			episode = newTitle.split(" Part ")[1].split("\\s")[0];
			if(episode.equalsIgnoreCase("one")) { episodeInt = 1; }
			else if(episode.equalsIgnoreCase("two")) { episodeInt = 2; }
			else if(episode.equalsIgnoreCase("three")) { episodeInt = 3; }
			else if(episode.equalsIgnoreCase("four")) { episodeInt = 4; }
			else if(episode.equalsIgnoreCase("five")) { episodeInt = 5; }
			else if(episode.equalsIgnoreCase("six")) { episodeInt = 6; }
			else if(episode.equalsIgnoreCase("seven")) { episodeInt = 7; }
			else if(episode.equalsIgnoreCase("eight")) { episodeInt = 8; }
			else if(episode.equalsIgnoreCase("nine")) { episodeInt = 9; }
			else if(episode.equalsIgnoreCase("ten")) { episodeInt = 10; }
			else if(episode.equalsIgnoreCase("eleven")) { episodeInt = 11; }
			else if(episode.equalsIgnoreCase("twelve")) { episodeInt = 12; }
			else if(episode.equalsIgnoreCase("thirteen")) { episodeInt = 13; }
			else if(episode.equalsIgnoreCase("fourteen")) { episodeInt = 14; }
			else if(episode.equalsIgnoreCase("fifteen")) { episodeInt = 15; }
			else if(episode.equalsIgnoreCase("sixteen")) { episodeInt = 16; }
			else if(episode.equalsIgnoreCase("seventeen")) { episodeInt = 17; }
			else if(episode.equalsIgnoreCase("eighteen")) { episodeInt = 18; }
			else if(episode.equalsIgnoreCase("nineteen")) { episodeInt = 19; }
			else if(episode.equalsIgnoreCase("twenty")) { episodeInt = 20; }
			else {
				LOGGER.info("Invalid number format for " + episode + " (or higher than twenty) in " + newTitle);
				return;
			}
		}
		doneParsing(title, 1, episodeInt, link);
	}

	private void doneParsing(String title, int seasonInt, int episodeInt, String link) {
		LOGGER.finest(myFeed.getLabel() + " has " + title + " season " + seasonInt + " episode " + episodeInt);
		Show show = null;
		for(int i=0;i<this.rssShows.size();i++) {
			if(rssShows.get(i).getTitle().equals(title)) {
				show = rssShows.get(i);
			}
		}
		if(show==null) {
			show = new Show(title);
			rssShows.add(show);
		}
		Season season = show.findSeason(seasonInt); 
		if(season==null) {
			season = show.addSeason(seasonInt);
		}
		season.addEpisode(episodeInt, link, myFeed.getLabel());
	}
}